import datetime
from decimal import Decimal
from django.core import serializers
from django.core.exceptions import ObjectDoesNotExist
from django.db.models.query import QuerySet
from django.forms import forms
from django.http import HttpResponse, HttpResponseRedirect
from django.shortcuts import render_to_response, redirect
from django.template import response
from django.template.context import Context, RequestContext
from django.utils import simplejson
import datetime
from django.utils.datetime_safe import date
from django.utils.encoding import force_unicode
from django.utils.functional import Promise
from django.views.decorators.http import require_http_methods, require_GET
import sys
import time
from exams.models import Exam, User, Role, Exam_Result, User_Exams, Question, Answer
from django.utils import simplejson
import datetime
from django.forms import *



""" Exams index page - shows all available exams to students
    or exams created by a teacher
"""

# a list of all exams => /exams/
def index(request):
    title = 'Educator 3000 - Where people learn or die'
    uid = 1 # should come from authentication
    exams_results = list(Exam.objects.all())
    exams_open = {}
    for exam in exams_results:
        exams_open[exam.id] = is_exam_open(exam.id)
    user = User.objects.get(id=uid)
    print exams_open
    ctx = {'title': title, 'exams_list': exams_results, 'user': user, 'exam_open': exams_open}

    a = 5.0
    b = 3.0
    print a/b

    return render_to_response('exams/index.html', ctx)

""" Exam page - CRUD

"""
#show an exam by id => /exams/1

class QuestionForm (ModelForm):
    class Meta:
        model = Question

class PartialQuestionForm(ModelForm):
    class Meta:
        model = Question
        fields = ('question',)

class AnswerForm (ModelForm):
    class Meta:
        model = Answer
        fields = ('answer','correct_answer')

class ExamForm (ModelForm):
    class Meta:
        model = Exam
        fields = ('remarks', 'course', 'pub_date', 'begin_time', 'end_time')



def show(request, exam_id, user_id):
    exam_result = Exam.objects.select_related().get(pk=exam_id)
    user = User.objects.get(id__exact=user_id)
    exam = Exam.objects.get(id__exact=exam_id)
    try:
        user_exams = User_Exams.objects.get(user_id__exact=user_id, exam_id__exact=exam_id)
        done = True
    except ObjectDoesNotExist:
        user_exams = User_Exams(user_id=user, exam_id=exam, grade=0)
        user_exams.save()
        done = False

    # DEBUG
    #done = False
    exam_time = (exam.end_time.hour - exam.begin_time.hour)

    # if exam is done return exam info for user, else take the exam
    if not done:
        return render_to_response('exams/take.html', {'exam_result': exam_result, 'exam_time':exam_time,
                                                      'user_id': user.id, 'exam_id': exam_id})
    else:
        return render_to_response('exams/show.html', {'exam_result': exam_result, 'taken':done,
                                                      'user':user, 'exam':exam})

#create or update exam

def create_exam(request):
    print request.method

    formset = ExamForm()

    return render_to_response('exams/create.html', {'ExamForm': formset, 'exam_id': (Exam.objects.all()).count()})

#update an exam => /exam/id
def create_ex(request, exam_id):
    print "Hallo"
    formset = ExamForm(request.POST)
    if formset.is_valid():
        now = datetime.datetime.now()
        course = formset.cleaned_data['course']
        create_date = now.strftime("%Y-%m-%d")
        pub_date = formset.cleaned_data['pub_date']
        begin_time = formset.cleaned_data['begin_time']
        end_time = formset.cleaned_data['end_time']
        remarks = formset.cleaned_data['remarks']

        exam =  Exam(remarks=remarks, course=course,
            create_date=create_date, pub_date=pub_date,
            begin_time=begin_time, end_time=end_time, dept_id=1, type_id=3)

        exam.save()

        return render_to_response('exams/create_question.html', {'exam': exam, 'exam_id': (Exam.objects.all()).count()})

def update_exam(request, exam_id):
    if request.method == 'PUT':
        pass

#delete an exam => /exam/id
@require_http_methods(["DELETE"])
def delete_exam(request, num=1):
    pass #probably will not be implemented unless it is an exam that has no questions and no data



#create or update question
def create_question(request, exam_id):
    print "Godan daginn"
    if request.method == "POST":
        qform = PartialQuestionForm(request.POST)
        if qform.is_valid():
            examid = exam_id
            exam = Exam.objects.get(id=examid)
            print exam
            questiont = qform.cleaned_data['question']
            question = Question(exam = exam, question = questiont)
            question.save()
            print question.id
            render_to_response('exams/create_question.html', {'exam': exam,
                                                              'exam_id': (Exam.objects.all()).count(),
                                                              'QuestionForm': qform,
                                                              'question_id': question.id
                                                              })
    else:
        print "Question get"
        qform = PartialQuestionForm()

    return render_to_response('exams/create_question.html', {'QuestionForm': qform,
                                                             'exam_id': (Exam.objects.all()).count(),
                                                             'question_id' : Question.objects.all().count()+1
                                                             })

#delete question
def delete_question(request, exam_id):
    pass

#create or update answer
def create_answer(request, question_id):
    questionid = question_id
    question = Question.objects.get(id=questionid)
    examid = question.exam.id
    exam = Exam.objects.get(id=examid)
    if request.method == "POST":
        aform = AnswerForm(request.POST)
        if aform.is_valid():
            answert = aform.data['answer']
            correct = aform.data['correct_answer']
            answer = Answer(question = question, answer = answert, correct_answer = correct)
            answer.save()

            render_to_response('exams/create_question.html', {'AnswerForm': aform,
                                                              'exam': exam
                                                              })
    else:
        aform = AnswerForm()

    return render_to_response('exams/create_answer.html', {'AnswerForm': aform,
                                                             'exam': exam,
                                                             'Question': question,
                                                             'examid': exam.id
                                                             })

def create_exam2(request) :
    now = datetime.datetime.now()
    if request.method == 'POST': # If the form has been submitted...
        course = request.POST["course"]
        create_date = now.strftime("%Y-%m-%d")
        pub_date = request.POST["pub_date"]
        begin_time = request.POST["begin_time"]
        end_time = request.POST["end_time"]
        remarks = request.POST["remarks"]

        exam = Exam(remarks=remarks, course=course,
            create_date=create_date, pub_date=pub_date,
            begin_time=begin_time, end_time=end_time, dept_id=1, type_id=3)
        exam.save()
        return HttpResponseRedirect("../../exams/create_question2/" + str(exam.id))
    else:
        exam = Exam()
        exam.end_date = now.strftime("%Y-%m-%d %H:%M")

        r = RequestContext(request, {
            "exam": exam,
            })

    return render_to_response("exams/create.html", r)

def create_question2(request, exam_id) :
    print "Konukona"
    if request.method == 'POST': # If the form has been submitted...

        question_text = request.POST["question"]
        examId = exam_id
        exam_temp = Exam.objects.get(id=examId)
        question = Question(exam = exam_temp, question = question_text)
        question.save()
        answer1 = request.POST["answer1"]
        answer2 = request.POST["answer2"]
        answer3 = request.POST["answer3"]
        answer4 = request.POST["answer4"]
        answer5 = request.POST["answer5"]
        if request.POST.get('correct') == 'correct1':
            answer = Answer(answer=answer1, correct_answer = True, question=question)
            answer.save()
            answer = Answer(answer=answer2, correct_answer = False, question=question)
            answer.save()
            answer = Answer(answer=answer3, correct_answer = False, question=question)
            answer.save()
            answer = Answer(answer=answer4, correct_answer = False, question=question)
            answer.save()
            answer = Answer(answer=answer5, correct_answer = False, question=question)
            answer.save()
        elif request.POST.get('correct') == 'correct2':
            answer = Answer(answer=answer1, correct_answer = False, question=question)
            answer.save()
            answer = Answer(answer=answer2, correct_answer = True, question=question)
            answer.save()
            answer = Answer(answer=answer3, correct_answer = False, question=question)
            answer.save()
            answer = Answer(answer=answer4, correct_answer = False, question=question)
            answer.save()
            answer = Answer(answer=answer5, correct_answer = False, question=question)
            answer.save()
        elif request.POST.get('correct') == 'correct3':
            answer = Answer(answer=answer1, correct_answer = False, question=question)
            answer.save()
            answer = Answer(answer=answer2, correct_answer = False, question=question)
            answer.save()
            answer = Answer(answer=answer3, correct_answer = True, question=question)
            answer.save()
            answer = Answer(answer=answer4, correct_answer = False, question=question)
            answer.save()
            answer = Answer(answer=answer5, correct_answer = False, question=question)
            answer.save()
        elif request.POST.get('correct') == 'correct4':
            answer = Answer(answer=answer1, correct_answer = False, question=question)
            answer.save()
            answer = Answer(answer=answer2, correct_answer = False, question=question)
            answer.save()
            answer = Answer(answer=answer3, correct_answer = False, question=question)
            answer.save()
            answer = Answer(answer=answer4, correct_answer = True, question=question)
            answer.save()
            answer = Answer(answer=answer5, correct_answer = False, question=question)
            answer.save()
        elif request.POST.get('correct') == 'correct5':
            answer = Answer(answer=answer1, correct_answer = False, question=question)
            answer.save()
            answer = Answer(answer=answer2, correct_answer = False, question=question)
            answer.save()
            answer = Answer(answer=answer3, correct_answer = False, question=question)
            answer.save()
            answer = Answer(answer=answer4, correct_answer = False, question=question)
            answer.save()
            answer = Answer(answer=answer5, correct_answer = True, question=question)
            answer.save()

        return HttpResponseRedirect("../../exams/create_question2/" + str(exam_temp.id))
    else:
        question = Question()
        answer = Answer()
        examId = exam_id
        exam = Exam.objects.get(id=examId)

        r = RequestContext(request, {
            "question": question,
            "answer" : answer,
            "examId" : str(exam.id),
            })

    return render_to_response("exams/create_question2.html", r)

#delete question
def delete_answer(request, question_id):
    pass

""" Exam results
    Students should see how they stand compared to others
    Teacher should see how many participated and other useful stats
"""

#get all user exams
def my_exams(request, uid):
    #we should get the user id from session after authentication
    user = User.objects.get(pk=uid)
    exams_ids = User_Exams.objects.filter(user_id__exact=uid)

    exams = []
    grades = []
    for id in exams_ids:
        grades.append(id.grade)
        exams.append(Exam.objects.get(id=id.exam_id_id))

    #TODO check grades column, must be Decimal
    average = float(grades)/float(exams_ids.count())
    return render_to_response('exams/user.html', {'user': user, 'exams': exams,
                                                  'count':exams_ids.count(), 'average': average })

def show_user_exam(request, user_id, exam_id):
    exam = Exam.objects.select_related().get(id__exact=exam_id)
    user_results = Exam_Result.objects.filter(exam_id__exact=exam_id, user_id__exact=user_id)
    user_exam = exam.user_exams_set.filter(exam_id__exact=exam_id).get()
    x = get_score_for_user(user_id, exam_id)
    print x
    questions = {}
    q_count = 0
    a_count = 0
    for q in exam.question_set.all():
        answers = {}
        q_count += 1
        for a in q.answer_set.all():
            correct = {}
            correct['exam'] = a.correct_answer
            ua = user_results.get(question_id=q.id, answer_id=a.id)
            correct['user'] = ua.correct_answer
            answers[a.answer] = correct
            if ua.correct_answer == True and a.correct_answer == True: a_count += 1
        questions[q.question] = answers
    questions[q.question] = answers
    grade = str(Decimal(a_count)/Decimal(q_count) * 100) + '%'
    return render_to_response('exams/user_show_exam.html', { 'user':user_id, 'exam':exam,
                                                             'questions': questions, 'grade': grade,
                                                             'correct_answers': a_count, 'question_count': q_count})

def show_user_exam_stats(request, user_id, exam_id):
    #how many students have taken the exam
    students = list(User.objects.filter(role=2))
    student_exam = User_Exams.objects.filter(exam_id=exam_id)
    exam = Exam.objects.get(id=exam_id)
    student_grade = User_Exams.objects.get(user_id__exact=user_id, exam_id__exact=exam_id)
    grades = []
    for student in students:
        try:
            item =student_exam.get(user_id__exact=student.id)
            grades.append(item.grade)
        except ObjectDoesNotExist:
            pass
    # get the average
    total_grades = sum(grades)
    average = 0
    if total_grades != 0:
        average = total_grades / student_exam.count()
    # return the user score as well for comparison
    return render_to_response('exams/user_stats_exam.html', { 'student_count': student_exam.count(),
                                                              'average' : average, 'exam':exam,
                                                               'student_grade': student_grade.grade})

# returns a dict with total question count and correctly answered questions
def get_score_for_user(user_id, exam_id):
    # correctly answered questions
    exam = Exam.objects.select_related().get(id__exact=exam_id)
    question_count = exam.question_set.count()
    user_results = Exam_Result.objects.filter(exam_id__exact=exam_id, user_id__exact=user_id)
    q_count = 0
    a_count = 0
    for q in exam.question_set.all():
        q_count += 1
        for a in q.answer_set.all():
            ua = user_results.get(question_id=q.id, answer_id=a.id)
            if ua.correct_answer == True and a.correct_answer == True: a_count += 1
    return {'question_count': q_count, 'correct': a_count}

# get_object_or_404() function takes a Django model as its first argument and an arbitrary number of keyword arguments,
# which it passes to the module's get() function. It raises Http404 if the object doesn't exist.

#create - POST
#read - GET
#update - PUT
#delete - DELETE

def sandbox(request):
    return render_to_response('exams/sandbox.html')

def ajax_test(request):
    if request.is_ajax():
        if request.method == 'GET':
            message = "This is a GET request"
        elif request.method == 'POST':
            message = "This is a POST request"
            # This fucker doesn't work
            print request.POST
    else:
        message = "No XHR"
    return HttpResponse(message)

def post_test(request):
    print 'request...'
    if request.is_ajax():
        print request.POST
        #qid = request.POST.get('qid', None)
        #aid = request.POST.get('aid', None)
    else:
        print 'heloooooooooooooooo'

    return HttpResponse("yyyyyyyyyyyyoooooooo")

# submit answer via Ajax
def post_answer(request):
    print 'request...'
    if request.is_ajax():
        uid = request.POST.get('uid', None)
        eid = request.POST.get('eid', None)
        aid = request.POST.get('aid', None)
        qid = request.POST.get('qid', None)

        print eid,uid,qid,aid

        try:
            #first set all object to false
            Exam_Result.objects.filter(user_id=uid, exam_id=eid, question_id=qid).update(correct_answer=False)
            #then get the answer and set to true
            ex = Exam_Result.objects.get(user_id=uid, exam_id=eid, question_id=qid, answer_id=aid)
            ex.correct_answer = True
            ex.save()
        except Exam_Result.DoesNotExist as inst:
            print inst
            print 'no entry'
            try:
                exam = Exam.objects.get(id=eid)
                user = User.objects.get(id=uid)
                question = Question.objects.get(id=qid)
                answer = Answer.objects.get(id=aid)
                exx = Exam_Result(user_id=user, exam_id=exam, question_id=question,
                    answer_id=answer, correct_answer=True)
                exx.save()
                print 'saved!'
            except Exception as ex:
                print ex


#correct_answer = models.BooleanField()
    else:
        return HttpResponse("This is an ajax request")

    return HttpResponse("ok")

"""
    Methods
"""

# returns exam questions as json with question as key and answers as a collection of values
def exam_collection_to_json(obj):
    dict = {}
    for i in obj.question_set.all():
        q_list = []
        for n in i.answer_set.get_query_set():
            q_list.append(n.answer)
        dict[i.question] = q_list
    return simplejson.dumps(dict)

# print exams collection
def p_exam(obj):
    for q in obj.question_set.all():
        print 'Q > ' + q.question
        for a in q.answer_set.get_query_set():
            print 'A > ' + a.answer

#returns a list of correct answers to a question
def correct_answers(exam_id, question_id):
    exam = Exam.objects.select_related().get(id=exam_id)
    q_list = exam.question_set.get(id=question_id)
    correct = []
    for answer in q_list.answer_set.all():
        if answer.correct_answer==True: correct.append(answer.id)
    return simplejson.dumps(correct)

# check if exam date is today
def is_exam_open(exam_id):
    exam = Exam.objects.select_related().get(id=exam_id)
    today = date.fromtimestamp(time.time())
    return  exam.pub_date > today

def exam_when_open(exam_id):
    exam = Exam.objects.select_related().get(id=exam_id)
    #return exam_in.min()

def submit_question(request):
    # request should hold user_id, exam_id, question_id, answer_id
    if request.is_ajax():
        uid = request.POST.get('user_id', None)
        eid = request.POST.get('exam_id', None)
        qid = request.POST.get('question_id', None)
        aid = request.POST.get('answer_id', None)
        correct = True

        #get all answers to a question
        #ex_results = Exam_Result.objects.get(exam_id=eid, user_id=uid, question_id=qid,
        #    answer_id=aid, correct_answer=correct)
        #if ex_results == None:
        #    result = Exam_Result(exam_id=eid, user_id=uid, question_id=qid,
        #        answer_id=aid, correct_answer=correct)
        #    result.save()
        #else:
        #    ex_results.correct_answer = correct
        #    ex_results.save()
        return "ok"
    else:
        return HttpResponse(404)

def submit_exam(request, user_id, exam_id):
    exam = Exam.objects.select_related().get(id=exam_id)
    questions = exam.question_set.all()

    for q in questions:
        for a in q.answer_set.all():
            try:
                answer = Exam_Result.objects.get(user_id=user_id, exam_id=exam_id,
                    question_id=q.id, answer_id=a.id)
                print "this question " + str(q.id) + " has been answered. Answer id " + str(a.id)
            except:
                try:
                    exam = Exam.objects.get(id=exam_id)
                    user = User.objects.get(id=user_id)
                    question = Question.objects.get(id=q.id)
                    answer = Answer.objects.get(id=a.id)
                    exx = Exam_Result(user_id=user, exam_id=exam, question_id=question,
                        answer_id=answer, correct_answer=False)
                    exx.save()
                    print "this question " + str(q.id)+ " has NOT been answered, Answer id " + str(a.id)
                except Exception as ex:
                    print ex

    #calculate user score
    score = get_score_for_user(user_id,exam_id)

    user_result = User_Exams.objects.get(user_id__exact=user_id, exam_id__exact=exam_id)

    # TODO grades column has to be Decimal to accept float
    #user_result.grade = float(score['question_count']) / float(score['correct'])

    return redirect('/exams/')